package com.usian.search.service.impl;

import com.usian.article.feign.ArticleFeign;
import com.usian.common.enums.AppHttpCodeEnum;
import com.usian.common.exception.LeadException;
import com.usian.common.threadlocal.UserThreadLocalUtils;
import com.usian.common.util.JsonUtils;
import com.usian.model.article.dtos.ArticleDto;
import com.usian.model.search.dtos.UserSearchDto;
import com.usian.search.service.ApArticleSearchService;
import com.usian.search.service.IApUserSearchService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
public class ApArticleSearchServiceImpl implements ApArticleSearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private String indexName = "app_info_article";
    /**
     * 把db数据导入es
     * @throws
     */
    @Override
    public void createIndex(ArticleDto articleDto) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", articleDto.getId());
        map.put("publishTime", articleDto.getPublishTime());
        map.put("layout", articleDto.getLayout());
        map.put("images", articleDto.getImages());
        map.put("authorId", articleDto.getAuthorId());
        map.put("title", articleDto.getTitle());
//转json数据
        String jsonStr = JsonUtils.toString(map);
        log.info("articleJson is {}",jsonStr);
        IndexRequest indexRequest = new IndexRequest(indexName).id(articleDto.getId().toString());
        indexRequest.source(jsonStr, XContentType.JSON);
        //导入索引库
        try {
            restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }    }

    @Autowired
    private IApUserSearchService apUserSearchService;

    @Override
    public List<ArticleDto> esArticleSearch(UserSearchDto dto) {
        //1、参数校验
        if(dto==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //获取用户id
        Integer userId = UserThreadLocalUtils.getUserId();
        //异步记录搜索关键字
        apUserSearchService.saveUserSearch(dto,userId);

        //根据标题模糊分页查询
        //构建查询请求对象，指定查询的索引名称
        SearchRequest searchRequest = new SearchRequest("app_info_article");
        //创建查询条件构建器SearchSourceBuilder
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //根据标题模糊查询
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", dto.getSearchWords()).operator(Operator.AND);
        boolQuery.must(matchQueryBuilder);
        //小于当前的时间
        if(dto.getMinBehotTime() != null){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lte(dto.getMinBehotTime());
            boolQuery.filter(rangeQueryBuilder);
        }
        sourceBuilder.query(boolQuery);
        //按照发布时间倒序排序
        sourceBuilder.sort("publishTime", SortOrder.DESC);
        //分页查询
        sourceBuilder.from(dto.getFromIndex());
        sourceBuilder.size(dto.getPageSize());
        searchRequest.source(sourceBuilder);

        //查询,获取查询结果
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //3.封装数据  获取Hits数据
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<ArticleDto> articleList = new ArrayList<>();
        for (SearchHit searchHit : hits) {
            String sourceAsString = searchHit.getSourceAsString();
            //转为java对象
            ArticleDto articleDto= JsonUtils.toBean(sourceAsString, ArticleDto.class);
            articleList.add(articleDto);
        }
        return articleList;
    }

    @Autowired
    private ArticleFeign articleFeign;

    @Override
    public void ImportOneArticle2Es(long articleId) {
        ArticleDto articleDto = articleFeign.findByIdArticle(articleId);
        //同步文章数据到索引库
        createIndex(articleDto);
    }


    //调用方法修改isDown状态   0-下架   1-上架
    //wmNewsId
    @Override
    public void ArticleUpDown(Integer wmNewsId, Integer enable) {
        //根据自媒体文章id，查询app文章
        ArticleDto articleDto = articleFeign.findByWemediaId(wmNewsId);
        if (enable == 1) {
            //上架
            createIndex(articleDto);
        }else {
            //下架
            deleteIndex(articleDto.getId());
        }
    }

    /*
    * 文章下架删除索引库
    * */
    private void deleteIndex(Long id) {
        DeleteRequest deleteRequest = new DeleteRequest(indexName).id(id.toString());
        try {
            restHighLevelClient.delete(deleteRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"删除索引库数据库失败");
        }
    }
}

